<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Vue | fengrixin</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/favicon.ico">
    <script>
         (function(){
            var html = document.createElement('script');
            html.src = 'https://www.googletagmanager.com/gtag/js?id=UA-166891571-1';
            var script = document.getElementsByTagName('script')[0]'
            script.parentNode.insertBefore(html, script);
            
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments)}
            gtag('js', new Date());
            gtag('config', 'UA-166891571-1');
         })();
        </script>
    <meta name="description" content="I don't know anything with certainty, but seeing the stars makes me dream.">
    <meta name="keywords" content="冯日新, fengrixin, rixin, 飘渺云轩">
    <meta name="author" content="rixin, s2675563468, fengrixin@yeah.net">
    <meta name="copyright" content="rixin">
    <meta name="renderer" content="webkit">
    
    <link rel="preload" href="/assets/css/0.styles.52cdc27a.css" as="style"><link rel="preload" href="/assets/js/app.0696c23a.js" as="script"><link rel="preload" href="/assets/js/2.96f039f8.js" as="script"><link rel="preload" href="/assets/js/26.7ae2d77c.js" as="script"><link rel="prefetch" href="/assets/js/10.473b7d15.js"><link rel="prefetch" href="/assets/js/11.0c193dec.js"><link rel="prefetch" href="/assets/js/12.c4d9d484.js"><link rel="prefetch" href="/assets/js/13.dce50cfa.js"><link rel="prefetch" href="/assets/js/14.eecb5cc3.js"><link rel="prefetch" href="/assets/js/15.e0473034.js"><link rel="prefetch" href="/assets/js/16.25b14741.js"><link rel="prefetch" href="/assets/js/17.c016c8f3.js"><link rel="prefetch" href="/assets/js/18.71195568.js"><link rel="prefetch" href="/assets/js/19.1dfd44c0.js"><link rel="prefetch" href="/assets/js/20.abde37ca.js"><link rel="prefetch" href="/assets/js/21.af59917b.js"><link rel="prefetch" href="/assets/js/22.d2f7b52b.js"><link rel="prefetch" href="/assets/js/23.ec5c07a5.js"><link rel="prefetch" href="/assets/js/24.eae97f7d.js"><link rel="prefetch" href="/assets/js/25.2f09818a.js"><link rel="prefetch" href="/assets/js/27.a3963c70.js"><link rel="prefetch" href="/assets/js/28.eadcc4e5.js"><link rel="prefetch" href="/assets/js/29.61cf8d1d.js"><link rel="prefetch" href="/assets/js/3.dd8204a7.js"><link rel="prefetch" href="/assets/js/30.7db889fa.js"><link rel="prefetch" href="/assets/js/31.fb075f3c.js"><link rel="prefetch" href="/assets/js/4.cf123337.js"><link rel="prefetch" href="/assets/js/5.abe0fc83.js"><link rel="prefetch" href="/assets/js/6.d9ded6eb.js"><link rel="prefetch" href="/assets/js/7.a054e416.js"><link rel="prefetch" href="/assets/js/8.f0b3a07f.js"><link rel="prefetch" href="/assets/js/9.f6495dca.js">
    <link rel="stylesheet" href="/assets/css/0.styles.52cdc27a.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">fengrixin</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="地基" class="dropdown-title"><span class="title">地基</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/algorithm/" class="nav-link">数据结构和算法</a></li><li class="dropdown-item"><!----> <a href="/learn/browser/" class="nav-link">浏览器工作原理</a></li><li class="dropdown-item"><!----> <a href="/learn/js/es6.html" class="nav-link">JavaScript</a></li><li class="dropdown-item"><!----> <a href="/learn/css/" class="nav-link">CSS</a></li><li class="dropdown-item"><!----> <a href="/learn/html/" class="nav-link">HTML</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="楼层" class="dropdown-title"><span class="title">楼层</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/vue/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Vue</a></li><li class="dropdown-item"><!----> <a href="/learn/node/" class="nav-link">Node.js</a></li><li class="dropdown-item"><!----> <a href="/learn/mini/index.html" class="nav-link">小程序</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电梯" class="dropdown-title"><span class="title">电梯</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/tools/chain.html" class="nav-link">工具链</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/publish.html" class="nav-link">发布系统</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/monitor.html" class="nav-link">监控系统</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="看一看" class="dropdown-title"><span class="title">看一看</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>仓库</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/watch/repository.html" class="nav-link">第三方库</a></li><li class="dropdown-subitem"><a href="/watch/website.html" class="nav-link">好玩的网站</a></li><li class="dropdown-subitem"><a href="/watch/article.html" class="nav-link">牛掰的文章</a></li><li class="dropdown-subitem"><a href="/watch/plugin.html" class="nav-link">扩展&amp;插件</a></li></ul></li><li class="dropdown-item"><h4>作品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://www.5you.com/apk/384161.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微冷知识
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><a href="https://github.com/fengrixin" target="_blank" rel="noopener noreferrer" class="nav-link external">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="地基" class="dropdown-title"><span class="title">地基</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/algorithm/" class="nav-link">数据结构和算法</a></li><li class="dropdown-item"><!----> <a href="/learn/browser/" class="nav-link">浏览器工作原理</a></li><li class="dropdown-item"><!----> <a href="/learn/js/es6.html" class="nav-link">JavaScript</a></li><li class="dropdown-item"><!----> <a href="/learn/css/" class="nav-link">CSS</a></li><li class="dropdown-item"><!----> <a href="/learn/html/" class="nav-link">HTML</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="楼层" class="dropdown-title"><span class="title">楼层</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/vue/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Vue</a></li><li class="dropdown-item"><!----> <a href="/learn/node/" class="nav-link">Node.js</a></li><li class="dropdown-item"><!----> <a href="/learn/mini/index.html" class="nav-link">小程序</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="电梯" class="dropdown-title"><span class="title">电梯</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/learn/tools/chain.html" class="nav-link">工具链</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/publish.html" class="nav-link">发布系统</a></li><li class="dropdown-item"><!----> <a href="/learn/tools/monitor.html" class="nav-link">监控系统</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="看一看" class="dropdown-title"><span class="title">看一看</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>仓库</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/watch/repository.html" class="nav-link">第三方库</a></li><li class="dropdown-subitem"><a href="/watch/website.html" class="nav-link">好玩的网站</a></li><li class="dropdown-subitem"><a href="/watch/article.html" class="nav-link">牛掰的文章</a></li><li class="dropdown-subitem"><a href="/watch/plugin.html" class="nav-link">扩展&amp;插件</a></li></ul></li><li class="dropdown-item"><h4>作品</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="http://www.5you.com/apk/384161.html" target="_blank" rel="noopener noreferrer" class="nav-link external">
  微冷知识
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></li></ul></div></div><div class="nav-item"><a href="https://github.com/fengrixin" target="_blank" rel="noopener noreferrer" class="nav-link external">
  GitHub
  <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></div> <!----></nav>  <ul class="sidebar-links"><li><a href="/learn/vue/" aria-current="page" class="active sidebar-link">Vue</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/vue/#mvvm-数据驱动视图" class="sidebar-link">MVVM 数据驱动视图</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#响应式" class="sidebar-link">响应式</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/vue/#object-defineproperty" class="sidebar-link">Object.defineProperty</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#proxy" class="sidebar-link">Proxy</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/vue/#nexttick" class="sidebar-link">$nextTick</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#生命周期相关" class="sidebar-link">生命周期相关</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/vue/#props-methods-data-computed-watch-的初始化顺序" class="sidebar-link">props methods data computed watch 的初始化顺序</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/vue/#性能相关" class="sidebar-link">性能相关</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/vue/#异步加载组件" class="sidebar-link">异步加载组件</a></li></ul></li><li class="sidebar-sub-header"><a href="/learn/vue/#面试题" class="sidebar-link">面试题</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn/vue/#v-show-和-v-if-的区别" class="sidebar-link">v-show 和 v-if 的区别</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#为何-v-for-中要用-key" class="sidebar-link">为何 v-for 中要用 key</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#computed-和-watch-的区别" class="sidebar-link">computed 和 watch 的区别</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#为何组件-data-必须是一个函数" class="sidebar-link">为何组件 data 必须是一个函数</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#多个组件有相同的逻辑-如何抽离" class="sidebar-link">多个组件有相同的逻辑，如何抽离？</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#何时使用异步组件" class="sidebar-link">何时使用异步组件？</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#何时需要使用-keep-alive" class="sidebar-link">何时需要使用 keep-alive？</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#何时需要使用-beforedestroy" class="sidebar-link">何时需要使用 beforeDestroy</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#template-是什么" class="sidebar-link">template 是什么</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#描述组件渲染和更新的过程" class="sidebar-link">描述组件渲染和更新的过程</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#描述-vue-组件生命周期-有父子组件的情况" class="sidebar-link">描述 Vue 组件生命周期（有父子组件的情况）</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#vue-组件如何通讯" class="sidebar-link">Vue 组件如何通讯</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#双向数据绑定-v-model-的实现原理" class="sidebar-link">双向数据绑定 v-model 的实现原理</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#vue-router-两种路由模式的区别和原理" class="sidebar-link">Vue-Router 两种路由模式的区别和原理</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#基于-vue-设计一个购物车-组件结构-vuex-state-数据结构" class="sidebar-link">基于 Vue 设计一个购物车（组件结构，Vuex state 数据结构）</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#diff-算法的时间复杂度是如何优化到-o-n-的" class="sidebar-link">diff 算法的时间复杂度是如何优化到 O(n) 的？</a></li><li class="sidebar-sub-header"><a href="/learn/vue/#请用-vnode-描述一个-dom-结构" class="sidebar-link">请用 vnode 描述一个 DOM 结构</a></li></ul></li></ul></li><li><a href="/learn/vue/nuxt.html" class="sidebar-link">Nuxt</a></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h2 id="mvvm-数据驱动视图"><a href="#mvvm-数据驱动视图" class="header-anchor">#</a> MVVM 数据驱动视图</h2> <p>不再关注如何去操作 DOM，而更专注于数据和业务逻辑
<img src="https://img.imgdb.cn/item/6045b714cef1ec5e6f4e1dbb.png" alt=""></p> <h2 id="响应式"><a href="#响应式" class="header-anchor">#</a> 响应式</h2> <h3 id="object-defineproperty"><a href="#object-defineproperty" class="header-anchor">#</a> Object.defineProperty</h3> <p>缺点：</p> <ul><li>对象每个属性都劫持监听</li> <li>数组需在原型链上复写方法，拦截监听<div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">let</span> arrProto <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span><span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">)</span>
arrProto<span class="token punctuation">.</span><span class="token function-variable function">push</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token comment">// 触发视图更新后再调用原型链上的 Array 的 push 方法</span>
  <span class="token function">updateView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token class-name">Array</span><span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token operator">...</span>arguments<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre></div></li></ul> <h3 id="proxy"><a href="#proxy" class="header-anchor">#</a> Proxy</h3> <ul><li>优点：代理对象，对象的增删改都可监听</li> <li>缺点：兼容性不好，且无法 Polyfill</li></ul> <h2 id="nexttick"><a href="#nexttick" class="header-anchor">#</a> $nextTick</h2> <ul><li>Vue 是异步渲染
<ul><li>data 改变之后，DOM 不会立刻渲染</li> <li>页面渲染时会将 data 的修改做整合，一次性更新视图</li> <li>减少 DOM 操作次数，提高性能</li></ul></li> <li>$nextTick 会在 DOM 渲染之后被触发，以获取最新 DOM 节点</li></ul> <h2 id="生命周期相关"><a href="#生命周期相关" class="header-anchor">#</a> 生命周期相关</h2> <h3 id="props-methods-data-computed-watch-的初始化顺序"><a href="#props-methods-data-computed-watch-的初始化顺序" class="header-anchor">#</a> props methods data computed watch 的初始化顺序</h3> <div class="custom-block tip"><p class="custom-block-title">总结</p> <p>在 beforeCreate 和 created 之间进行初始化，它们的顺序为：<br>
props -&gt; methods -&gt; data -&gt; computed -&gt; watch</p></div> <p>查看源码可以得知，在 new Vue 的时候，Vue 会进行初始化</p> <p>vue/src/core/instance/index.js</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">import</span> <span class="token punctuation">{</span>initMixin<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./init'</span>

<span class="token keyword">function</span> <span class="token function">Vue</span><span class="token punctuation">(</span><span class="token parameter">options</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">!==</span> <span class="token string">'production'</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token keyword">instanceof</span> <span class="token class-name">Vue</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">'Vue is a constructor and should be called with the `new` keyword'</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">_init</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token function">initMixin</span><span class="token punctuation">(</span>Vue<span class="token punctuation">)</span>

<span class="token keyword">export</span> <span class="token keyword">default</span> Vue
</code></pre></div><p>在 initMixin 的时候 this._init() 会被挂在 Vue 的原型上，其中，_init() 的方法中有一段代码</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code>vm<span class="token punctuation">.</span>_self <span class="token operator">=</span> vm
<span class="token function">initLifecycle</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>
<span class="token function">initEvents</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>
<span class="token function">initRender</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>
<span class="token function">callHook</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> <span class="token string">'beforeCreate'</span><span class="token punctuation">)</span>
<span class="token function">initInjections</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span> <span class="token comment">// resolve injections before data/props</span>
<span class="token function">initState</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>
<span class="token function">initProvide</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>  <span class="token comment">// resolve provide after data/props</span>
<span class="token function">callHook</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> <span class="token string">'created'</span><span class="token punctuation">)</span>
</code></pre></div><p>进入 initState() 方法中，有那么一段非常清晰明确浅显易懂的代码</p> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token keyword">const</span> opts <span class="token operator">=</span> vm<span class="token punctuation">.</span>$options
<span class="token keyword">if</span><span class="token punctuation">(</span>opts<span class="token punctuation">.</span>props<span class="token punctuation">)</span> <span class="token function">initProps</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> opts<span class="token punctuation">.</span>props<span class="token punctuation">)</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>opts<span class="token punctuation">.</span>methods<span class="token punctuation">)</span> <span class="token function">initMethods</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> opts<span class="token punctuation">.</span>methods<span class="token punctuation">)</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>opts<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token function">initData</span><span class="token punctuation">(</span>vm<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
  <span class="token function">observe</span><span class="token punctuation">(</span>vm<span class="token punctuation">.</span>_data <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">true</span> <span class="token comment">/* asRootData */</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>opts<span class="token punctuation">.</span>computed<span class="token punctuation">)</span> <span class="token function">initComputed</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> opts<span class="token punctuation">.</span>computed<span class="token punctuation">)</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>opts<span class="token punctuation">.</span>watch <span class="token operator">&amp;&amp;</span> opts<span class="token punctuation">.</span>watch <span class="token operator">!==</span> nativeWatch<span class="token punctuation">)</span><span class="token punctuation">{</span>
  <span class="token function">initWatch</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span> opts<span class="token punctuation">.</span>watch<span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment">// vue/src/core/util/env.js</span>
<span class="token comment">// Firefox has a &quot;watch&quot; function onObject.prototype...</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> nativeWatch <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>watch
</code></pre></div><h2 id="性能相关"><a href="#性能相关" class="header-anchor">#</a> 性能相关</h2> <h3 id="异步加载组件"><a href="#异步加载组件" class="header-anchor">#</a> 异步加载组件</h3> <p>使用异步加载组件的方式，可以做到按需加载，在一些复杂的场景中，可以缩短渲染时间，提升用户体验</p> <ul><li>页面</li> <li>子组件</li></ul> <div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token function-variable function">asyncDemo</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./asyncDemo'</span><span class="token punctuation">)</span>
</code></pre></div><h2 id="面试题"><a href="#面试题" class="header-anchor">#</a> 面试题</h2> <h3 id="v-show-和-v-if-的区别"><a href="#v-show-和-v-if-的区别" class="header-anchor">#</a> v-show 和 v-if 的区别</h3> <ul><li>v-show 通过 CSS 的 display 控制显示和隐藏</li> <li>v-if 组件真正的渲染和销毁元素，而不是显示和隐藏</li> <li>频繁切换显示状态用 v-show，否则用 v-if</li></ul> <h3 id="为何-v-for-中要用-key"><a href="#为何-v-for-中要用-key" class="header-anchor">#</a> 为何 v-for 中要用 key</h3> <ul><li>必须用 key，别整 random 或 index 这两个货色</li> <li>diff 算法中会通过 tag 和 key 来判断 vnode 节点是否是同一个</li> <li>减少渲染次数，提升渲染性能</li> <li>v-for 不要和 v-if 一起使用（v-for 优先级比 v-if 高）</li></ul> <h3 id="computed-和-watch-的区别"><a href="#computed-和-watch-的区别" class="header-anchor">#</a> computed 和 watch 的区别</h3> <ul><li>computed 会把计算结果缓存起来，相关的 data 数据不变则不会重新计算，提高性能</li> <li>watch 一般用来监听数据的变化</li> <li>computed 会先于 watch 进行初始化</li></ul> <h3 id="为何组件-data-必须是一个函数"><a href="#为何组件-data-必须是一个函数" class="header-anchor">#</a> 为何组件 data 必须是一个函数</h3> <p>组件编译后实际上是一个 class，组件的使用相当于实例化</p> <p>如果 data 是一个对象，那么其中一个实例对象对 data 修改，都会影响到其他实例对象</p> <p>data 是函数的话就可以保证每个实例化对象都是独立的，不会相互影响</p> <h3 id="多个组件有相同的逻辑-如何抽离"><a href="#多个组件有相同的逻辑-如何抽离" class="header-anchor">#</a> 多个组件有相同的逻辑，如何抽离？</h3> <p>使用 mixins 混入，mixins 的缺点是命名不能相同，否则会冲突，项目大的时候不易排查问题</p> <h3 id="何时使用异步组件"><a href="#何时使用异步组件" class="header-anchor">#</a> 何时使用异步组件？</h3> <ul><li>加载复杂或者大组件时</li> <li>路由异步加载</li></ul> <h3 id="何时需要使用-keep-alive"><a href="#何时需要使用-keep-alive" class="header-anchor">#</a> 何时需要使用 keep-alive？</h3> <p>缓存组件，不需要重复渲染</p> <ul><li>多个静态 tab 页的切换</li> <li>优化性能</li></ul> <h3 id="何时需要使用-beforedestroy"><a href="#何时需要使用-beforedestroy" class="header-anchor">#</a> 何时需要使用 beforeDestroy</h3> <ul><li>解绑自定义事件</li> <li>清除定时器</li> <li>解绑自定义的 DOM 事件，如 window scroll 等</li></ul> <h3 id="template-是什么"><a href="#template-是什么" class="header-anchor">#</a> template 是什么</h3> <p>相当于一种模板语法，不是单纯的 html，它还有着指令、表达式，循环判断这些能力</p> <p>Vue 会把 template 编译成一个 render 函数，执行这个函数后会生成 VNode，也就是虚拟 DOM</p> <p>（Vue3 在编译的时候做了一定的优化，对需要改变的地方打一个标记，比如插值、判断、循环，这样 diff 的时候只需要比对有标记的地方即可）</p> <h3 id="描述组件渲染和更新的过程"><a href="#描述组件渲染和更新的过程" class="header-anchor">#</a> 描述组件渲染和更新的过程</h3> <h4 id="渲染过程"><a href="#渲染过程" class="header-anchor">#</a> 渲染过程</h4> <ul><li>解析模板为 render 函数（在开发环境就已经完成，vue-loader）</li> <li>触发响应式，监听 data 属性 getter setter</li> <li>执行 render 函数，生成 vnode，然后通过 patch(elem, vnode) 函数渲染在页面上</li></ul> <h4 id="更新过程"><a href="#更新过程" class="header-anchor">#</a> 更新过程</h4> <ul><li>修改 data，触发 setter（此前在 getter 中已经被监听）</li> <li>重新执行 render 函数，生成 newVnode</li> <li>patch(vnode, newVnode) 通过 diff 对比拿到需要更新的节点，渲染到页面上</li></ul> <p><img src="https://img.imgdb.cn/item/60478eb65aedab222ccad427.png" alt=""></p> <h3 id="描述-vue-组件生命周期-有父子组件的情况"><a href="#描述-vue-组件生命周期-有父子组件的情况" class="header-anchor">#</a> 描述 Vue 组件生命周期（有父子组件的情况）</h3> <ul><li><p>页面加载渲染</p> <p>beforeCreate -&gt; created -&gt; beforeMount -&gt; [beforeCreate -&gt; created - beforeMount -&gt; mounted] -&gt; mounted</p></li> <li><p>子组件更新</p> <p>beforeUpdate -&gt; [beforeUpdate -&gt; updated] -&gt; updated</p></li> <li><p>父组件更新</p> <p>beforeUpdate -&gt; updated</p></li> <li><p>页面销毁</p> <p>beforeDestroy -&gt; [beforeDestroy -&gt; destroyed] -&gt; destroyed</p></li></ul> <h3 id="vue-组件如何通讯"><a href="#vue-组件如何通讯" class="header-anchor">#</a> Vue 组件如何通讯</h3> <h4 id="父子组件间"><a href="#父子组件间" class="header-anchor">#</a> 父子组件间</h4> <ul><li>props 和 $emit</li></ul> <h4 id="父子-兄弟-不相关组件间"><a href="#父子-兄弟-不相关组件间" class="header-anchor">#</a> 父子/兄弟/不相关组件间</h4> <ul><li>Vuex</li> <li>Vue 本身就具备自定义事件的能力<div class="language-javascript extra-class"><pre class="language-javascript"><code><span class="token comment">// event.js</span>
<span class="token keyword">import</span> Vue <span class="token keyword">from</span> <span class="token string">'vue'</span>
<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">new</span> <span class="token class-name">Vue</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token comment">// xxx1.vue</span>
<span class="token keyword">import</span> event <span class="token keyword">from</span> <span class="token string">'./event.js'</span>
event<span class="token punctuation">.</span><span class="token function">$emit</span><span class="token punctuation">(</span><span class="token string">'onChange'</span><span class="token punctuation">,</span> <span class="token string">'value'</span><span class="token punctuation">)</span> <span class="token comment">// 触发自定义事件</span>

<span class="token comment">// xxx2.vue</span>
<span class="token keyword">import</span> event <span class="token keyword">from</span> <span class="token string">'./event.js'</span>
<span class="token function">mounted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">$on</span><span class="token punctuation">(</span><span class="token string">'onChange'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>changeValueHandler<span class="token punctuation">)</span> <span class="token comment">// 监听自定义事件</span>
<span class="token punctuation">}</span>
<span class="token function">changeValueHandler</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token comment">// value</span>
<span class="token punctuation">}</span>
<span class="token function">beforDestroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
  event<span class="token punctuation">.</span><span class="token function">$off</span><span class="token punctuation">(</span><span class="token string">'onChange'</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>changeValueHandler<span class="token punctuation">)</span> <span class="token comment">// 解绑事件，以免内存泄漏</span>
<span class="token punctuation">}</span>
</code></pre></div></li> <li>EventBus</li></ul> <h3 id="双向数据绑定-v-model-的实现原理"><a href="#双向数据绑定-v-model-的实现原理" class="header-anchor">#</a> 双向数据绑定 v-model 的实现原理</h3> <p>就输入框而言，在编译 template 的时候，会给输入框绑定一个 input 事件，实时更新 value，从而达到数据的双向绑定</p> <ul><li><p>input 元素的 value = this.name</p></li> <li><p>绑定 input 事件 this.name = $event.target.value</p></li> <li><p>data 更新触发 re-render</p></li> <li><p>修饰符：</p> <ul><li>v-model.trim 去除前后空格</li> <li>v-model.lazy 防抖</li> <li>v-model.number 转换为数字</li></ul></li></ul> <h3 id="vue-router-两种路由模式的区别和原理"><a href="#vue-router-两种路由模式的区别和原理" class="header-anchor">#</a> Vue-Router 两种路由模式的区别和原理</h3> <ul><li>hash
<ul><li>监听 window.onhashchange 事件，浏览器会记录 hash 变化</li> <li>刷新，hash 不会提交到服务端</li></ul></li> <li>history
<ul><li>history.pushState 切换路由</li> <li>window.onpopstate 监听路由</li> <li>需要服务端配合，否则刷新后会 404</li></ul></li></ul> <h3 id="基于-vue-设计一个购物车-组件结构-vuex-state-数据结构"><a href="#基于-vue-设计一个购物车-组件结构-vuex-state-数据结构" class="header-anchor">#</a> 基于 Vue 设计一个购物车（组件结构，Vuex state 数据结构）</h3> <h3 id="diff-算法的时间复杂度是如何优化到-o-n-的"><a href="#diff-算法的时间复杂度是如何优化到-o-n-的" class="header-anchor">#</a> diff 算法的时间复杂度是如何优化到 O(n) 的？</h3> <ul><li>只比较同一层级，不跨级比较</li> <li>tag 不相同，则直接删掉重建，不再深度比较</li> <li>tag 和 key，两者都相同，则认为是相同节点，不再深度比较</li></ul> <h3 id="请用-vnode-描述一个-dom-结构"><a href="#请用-vnode-描述一个-dom-结构" class="header-anchor">#</a> 请用 vnode 描述一个 DOM 结构</h3> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>app<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>container<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span><span class="token punctuation">&gt;</span></span>text<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span> <span class="token style-attr"><span class="token attr-name">style</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span><span class="token style language-css"><span class="token property">font-size</span><span class="token punctuation">:</span> 20px</span><span class="token punctuation">&quot;</span></span></span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">&gt;</span></span>a<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><div class="language-json5 extra-class"><pre class="language-json5"><code><span class="token punctuation">{</span>
  <span class="token property unquoted">tag</span><span class="token operator">:</span> <span class="token string">'div'</span><span class="token punctuation">,</span>
  <span class="token property unquoted">props</span><span class="token operator">:</span> <span class="token punctuation">{</span>
    <span class="token property unquoted">className</span><span class="token operator">:</span> <span class="token string">'container'</span><span class="token punctuation">,</span>
    <span class="token property unquoted">id</span><span class="token operator">:</span> <span class="token string">'app'</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token property unquoted">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      <span class="token property unquoted">tag</span><span class="token operator">:</span> <span class="token string">'p'</span><span class="token punctuation">,</span>
      <span class="token property unquoted">children</span><span class="token operator">:</span> <span class="token string">'text'</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span>
      <span class="token property unquoted">tag</span><span class="token operator">:</span> <span class="token string">'ul'</span><span class="token punctuation">,</span>
      <span class="token property unquoted">props</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property unquoted">style</span><span class="token operator">:</span> <span class="token string">'font-size: 20px'</span>
      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token property unquoted">children</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token punctuation">{</span><span class="token property unquoted">tag</span><span class="token operator">:</span> <span class="token string">'li'</span><span class="token punctuation">,</span> <span class="token property unquoted">children</span><span class="token operator">:</span> <span class="token string">'a'</span><span class="token punctuation">}</span>
      <span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">3/10/2021, 5:37:35 PM</span></div></footer> <div class="page-nav"><p class="inner"><!----> <span class="next"><a href="/learn/vue/nuxt.html">Nuxt</a>
      →
    </span></p></div> </main></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.0696c23a.js" defer></script><script src="/assets/js/2.96f039f8.js" defer></script><script src="/assets/js/26.7ae2d77c.js" defer></script>
  </body>
</html>
